#include "buffer.h"
//Buffer类的构造函数，初始化buffer_的大小为initBufferSize，readPos_和writePos_都为0
Buffer::Buffer(int initBufferSize):buffer_(initBufferSize),readPos_(0),writePos_(0)
{}
//Buffer类的ReadableBytes()函数，返回可读字节数，即writePos_ - readPos_
size_t Buffer::ReadableBytes() const
{
    //返回可读字节数，writePos_z指向下一个写入位置，readPos_指向下一个读取位置，两者之差正好是当前可读取的数据量
    return writePos_ - readPos_;
}
//Buffer类的WritableBytes()函数，返回可写字节数，即buffer_.size() - writePos_
size_t Buffer::WritableBytes() const 
{
    //用vector的总大小减去写指针的位置，就是可写的大小
    return buffer_.size() - writePos_;
}
//Buffer类的PrependablyBytes()函数，返回可前置写字节数，即readPos_
size_t Buffer::PrependablyBytes() const
{
    //前置操作 ：指在已读取数据的前面（缓冲区头部）添加新数据的操作，常用于网络编程中添加协议头、状态码等场景。
    //返回可前置写字节数，即readPos_
    return readPos_;
}
//Buffer类的Peek()函数，返回可读数据的起始位置，即BeginPtr_() + readPos_
const char* Buffer::Peek() const
{
    //返回可读数据的起始位置，即BeginPtr_() + readPos_
    return BeginPtr_() + readPos_;
}
//Buffer类的Retrieve()函数，len是已读取的字节数，将readPos_指针后移len个位置
void Buffer::Retrieve(size_t len)
{
    //断言len是否小于等于可读字节数
    assert(len <= ReadableBytes());
    //将readPos_指针后移len个位置
    readPos_ += len;
}
//Buffer类的RetrieveUntil()函数，将readPos_指针后移到end位置
void Buffer::RetrieveUntil(const char* end)
{
    //断言Peek()（当前可读数据的起始位置）是否小于等于end
    assert(Peek() <= end);
    //将readPos_指针后移到end位置
    Retrieve(end-Peek());
}
//Buffer类的RetrieveAll()函数，将readPos_和writePos_都设为0，清空缓冲区
void Buffer::RetrieveAll()
{
    //使用标准方式重置vector
    buffer_.clear();
    buffer_.resize(4096); // 重新调整到初始大小
    readPos_ = 0;
    writePos_ = 0;
}
//Buffer类的RetrieveAllToStr()函数，将缓冲区中的数据转换为字符串并返回
std::string Buffer::RetrieveAllToStr()
{
    //创建一个临时字符串，确保内容被正确复制
    std::string tempStr(Peek(), ReadableBytes());
    //将缓冲区清空
    RetrieveAll();
    //返回安全复制的字符串
    return tempStr;
}
//Buffer类的BeginWriteConst()函数，返回可写数据的起始位置，即BeginPtr_() + writePos_
const char* Buffer::BeginWriteConst() const
{
    //返回可写数据的起始位置，即BeginPtr_() + writePos_
    return BeginPtr_() + writePos_;
}
//Buffer类的BeginWrite()函数，返回可写数据的起始位置，即BeginPtr_() + writePos_
char* Buffer::BeginWrite()
{
    //返回可写数据的起始位置，即BeginPtr_() + writePos_
    return BeginPtr_() + writePos_;
}
//Buffer类的HasWritten()函数，将writePos_指针后移len个位置
void Buffer::HasWritten(size_t len)
{
    //将writePos_指针后移len个位置
    writePos_ += len;
}
//Buffer类的Append()函数，将字符串str添加到缓冲区中
void Buffer::Append(const std::string& str)
{
    //调用Append(const char* str,size_t len)函数，将字符串str添加到缓冲区中
    Append(str.data(),str.length());
}
//Buffer类的Append(const void* data,size_t len)函数，将数据data添加到缓冲区中
void Buffer::Append(const void* data,size_t len)
{
    //断言data是否为空
    assert(data);
    //将data转换为const char*类型，调用Append(const char* str,size_t len)函数，将data添加进缓冲区
    Append(static_cast<const char*>(data),len);
}
//Buffer类的Append(const char* str,size_t len)函数，将字符串str添加到缓冲区中
void Buffer::Append(const char* str,size_t len)
{
    //断言str是否为空
    assert(str);
    //确保缓冲区有足够的空间，能够容纳字符串str
    EnsureWriteable(len);
    //将str中的len个字符复制到缓冲区中
    std::copy(str,str+len,BeginWrite());
    //改变writePos_指针的位置
    HasWritten(len);
}
//Buffer类的Append(const Buffer& buff)函数，将一个缓冲区的未读数据无缝添加进当前缓冲区
void Buffer::Append(const Buffer& buff)
{
    //
    Append(buff.Peek(),buff.ReadableBytes());
}
//Buffer类的EnsureWriteable函数，确保缓冲区有空间能容纳len个字符
void Buffer::EnsureWriteable(size_t len)
{
    //如果当前可写数据的大小小于len
    if(WritableBytes() < len)
    {
        //扩容，确保缓冲区有足够的空间
        MakeSpace_(len);
    }
    //断言扩容后，可写数据的大小大于等于0
    assert(WritableBytes() >= 0);
}
//Buffer类的ReadFd函数，从文件描述符fd中读取数据，将数据添加到缓冲区中
ssize_t Buffer::ReadFd(int fd,int* saveErrno)
{
    //创建一个缓冲区，用于存储从文件描述符fd中读取的数据
    char buff[65535];
    //创建一个iovec结构体数组，用于分散存储要读取的数据
    //iov[0]，把数据放入Buffer结构体的缓冲区
    //iov[1]，把数据放入buff缓冲区
    struct iovec iov[2];
    //获取当前可写数据的大小
    const size_t writeable = WritableBytes();
    //将Buffer结构体的缓冲区的可写数据的起始位置赋值给iov[0].iov_base
    iov[0].iov_base = BeginPtr_() + writePos_;
    //可写入大小是writeable
    iov[0].iov_len = writeable;
    //将buff缓冲区的起始位置赋值给iov[1].iov_base
    iov[1].iov_base = buff;
    //可写入大小是buff缓冲区的大小
    iov[1].iov_len = sizeof(buff);
    //从fd读取数据，将数据分散存储到iov[0]和iov[1]中
    const ssize_t len = readv(fd,iov,2);
    //读取数据失败，获取错误码到saveErrno
    if(len < 0)
    {
        *saveErrno = errno;
    }
    //读取数据成功，但是获取的数据小于等于Buffer缓冲区可写数据的大小
    else if(static_cast<size_t>(len) <= writeable)
    {
        //将可写数据的指针后移len个位置
        writePos_ += len;
    }
    //读取数据成功，获取的数据大于Buffer缓冲区可写数据的大小
    else
    {
        //直接把Buffer的缓冲区干满
        writePos_ = buffer_.size();
        //将buff缓冲区中的数据添加到Buffer缓冲区中
        Append(buff,len - writeable);
    }
    //返回已经读取数据的大小
    return len;
}
//Buffer类的WriteFd函数，将缓冲区中的数据写入文件描述符fd中
ssize_t Buffer::WriteFd(int fd,int* saveErrno)
{
    //获取缓冲区中可读数据的大小
    size_t readSize = ReadableBytes();
    //将缓冲区中的数据写入文件描述符fd中
    ssize_t len = write(fd,Peek(),readSize);
    //如果len小于0，代表写入失败
    if(len < 0)
    {
        //获取错误码到saveErrno
        *saveErrno = errno;
        //返回len
        return len;
    }
    else 
    {
        //将readPos_指针后移len个位置
        readPos_ += len;
    }
    //返回已经写入数据的大小
    return len;
}
//Buffer类的BeginPtr_()函数，返回缓冲区的起始位置
char* Buffer::BeginPtr_()
{
    return &*buffer_.begin();
}
//Buffer类的BeginPtr_()函数，返回缓冲区的起始位置
const char* Buffer::BeginPtr_() const
{
    return &*buffer_.begin();
}
//Buffer类的MakeSpace_()函数，确保缓冲区有足够的空间
void Buffer::MakeSpace_(size_t len)
{
    //WritableBytes()函数返回尾部可写数据的大小
    //PrependablyBytes()函数返回头部可写数据的大小
    //判断判断整体可用空间（尾部+头部）是否小于所需空间 len
    if(WritableBytes() + PrependablyBytes() < len)
    {
        //如果整体可用空间小于所需空间，直接扩容，整体容量为当前写入位置writepos_加上所需空间len+1（预留安全位置）
        buffer_.resize(writePos_ + len + 1);
    }
    //可用空间充足时，压缩数据
    else 
    {
        //获取可读数据的大小
        size_t readble = ReadableBytes();
        
        // 创建临时副本存储数据，避免在移动过程中可能的内存问题
        std::vector<char> temp(buffer_.begin() + readPos_, buffer_.begin() + writePos_);
        
        // 清空原缓冲区
        buffer_.clear();
        buffer_.resize(4096 + temp.size()); // 确保有足够空间
        
        // 将临时数据复制回缓冲区起始位置
        std::copy(temp.begin(), temp.end(), buffer_.begin());
        
        //重置读写指针
        readPos_ = 0;
        writePos_ = temp.size();
        
        //断言可读数据的大小等于当前可读数据的大小
        assert(readble == ReadableBytes());
    }
}